package com.xiaozou.controller;

import cn.hutool.core.util.StrUtil;
import com.xiaozou.config.Config;
import com.xiaozou.dao.QwenRecordDaoService;
import com.xiaozou.dao.entity.DoubaoResultRecordEntity;
import com.xiaozou.domain.AnswerRsp;
import com.xiaozou.domain.ExportRow;
import com.xiaozou.domain.QuestionReq;
import com.xiaozou.enums.RecognizePoint;
import com.xiaozou.enums.TuringIndustry;
import com.xiaozou.service.IndustryAskMethodLoader;
import com.xiaozou.util.FileUt;
import com.xiaozou.util.HttpUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequiredArgsConstructor
public class TestController implements DisposableBean {

    private final QwenRecordDaoService qwenRecordDaoService;
    private final IndustryAskMethodLoader industryAskMethodLoader;

    // 外层线程池 - 处理行业问法任务
    private ExecutorService industryAskExecutor;
    // 内层线程池 - 处理问题处理任务
    private ExecutorService questionProcessingExecutor;

    // 初始化线程池
    @PostConstruct
    public void init() {
        // 外层线程池：固定线程数（根据CPU核心数调整）
        int corePoolSize = Math.max(2, Runtime.getRuntime().availableProcessors());
        industryAskExecutor = new ThreadPoolExecutor(
                corePoolSize,
                corePoolSize * 2,
                60L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(50),
                new CustomThreadFactory("IndustryAskPool"),
                new ThreadPoolExecutor.CallerRunsPolicy());

        // 内层线程池：较大的线程池处理IO密集型任务
        int maxThreads = 10;
        questionProcessingExecutor = new ThreadPoolExecutor(
                maxThreads / 2,
                maxThreads,
                60L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(200),
                new CustomThreadFactory("QProcessingPool"),
                new ThreadPoolExecutor.CallerRunsPolicy());
    }

    // 自定义线程工厂
    static class CustomThreadFactory implements ThreadFactory {
        private final String namePrefix;
        private final AtomicInteger threadCount = new AtomicInteger(1);

        CustomThreadFactory(String prefix) {
            this.namePrefix = prefix + "-Thread-";
        }

        @Override
        public Thread newThread(Runnable r) {
            Thread thread = new Thread(r, namePrefix + threadCount.getAndIncrement());
            thread.setDaemon(false);
            return thread;
        }
    }

    @GetMapping("test")
    public String test() {
        CompletableFuture.runAsync(()->{
            log.info("【主任务开始】总行业数: {}", TuringIndustry.values().length);
            List<CompletableFuture<Void>> futures = new ArrayList<>();
            for (TuringIndustry industry : TuringIndustry.values()) {
                // 为每个行业提交外层任务
                futures.add(CompletableFuture.runAsync(() -> handleIndustry(industry), industryAskExecutor));
            }
            // 等待所有外层任务完成
            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
                    .exceptionally(ex -> {
                        log.error("【主任务异常】", ex);
                        return null;
                    })
                    .join();
            log.info("【主任务完成】所有行业处理完毕");
        });
        return "success";
    }

    private void handleIndustry(TuringIndustry industry) {
        log.debug("【行业处理开始】行业: {}", industry.getName());
        List<String> askMethods = industryAskMethodLoader.getAskMethods(industry);
        log.info("【行业处理】行业: {}, 行为数: {}", industry.getName(), askMethods.size());
        List<CompletableFuture<Void>> methodFutures = askMethods.stream()
                .map(askMethod -> CompletableFuture.runAsync(
                        () -> handleIndustryAskMethod(industry, askMethod),
                        industryAskExecutor)
                )
                .collect(Collectors.toList());

        // 等待当前行业的所有问法处理完成
        CompletableFuture.allOf(methodFutures.toArray(new CompletableFuture[0]))
                .exceptionally(ex -> {
                    log.error("【行业处理异常】行业: {}, 异常: {}", industry.getName(), ex.getMessage());
                    return null;
                })
                .join();

        log.debug("【行业处理完成】行业: {}", industry.getName());
    }

    private void handleIndustryAskMethod(TuringIndustry industry, String askMethod) {
        log.info("【问法处理开始】行业: {}, 问法: {}", industry.getName(), askMethod);
        List<DoubaoResultRecordEntity> records = qwenRecordDaoService.list(
                industry.getCode(),
                askMethod,
                RecognizePoint.TURING_INDUSTRY.getDesc()
        );
        log.info("【问法处理】行业: {}, 问法: {}, 问题数: {}", industry.getName(), askMethod, records.size());
        // 准备收集结果
        List<ExportRow> rowList = new ArrayList<>(records.size());
        // 创建问题处理任务
        List<CompletableFuture<ExportRow>> questionFutures = records.stream()
                .map(entity -> CompletableFuture.supplyAsync(
                                () -> processQuestion(entity),
                                questionProcessingExecutor)
                        .exceptionally(ex -> {
                            log.error("【问题处理异常】问法: {}, 问题ID: {}, 异常: {}",
                                    askMethod, entity.getId(), ex.getMessage());
                            return null; // 返回null会被后续过滤
                        })
                )
                .collect(Collectors.toList());

        // 等待所有问题处理完成
        CompletableFuture.allOf(questionFutures.toArray(new CompletableFuture[0]))
                .thenApply(v -> questionFutures.stream()
                        .map(CompletableFuture::join)
                        .filter(Objects::nonNull)
                        .collect(Collectors.toList())
                )
                .thenAccept(results -> {
                    rowList.addAll(results);
                    log.debug("【问法处理】行业: {}, 问法: {}, 成功处理问题数: {}",
                            industry.getName(), askMethod, results.size());
                })
                .join();

        // 导出Excel
        try {
            String safeFileName = askMethod.replaceAll("[\\\\/:*?\"<>|]", "_") ;
            String directoryPath = Config.OUTPUT_EXCEL_FILE_ROOT_PATH + File.separator + industry.getName();
            String filePath = directoryPath + File.separator + safeFileName + ".xlsx"; // 最后只加一次后缀
            // ✅ 使用 Hutool 自动创建父级目录
            File destFile = new File(filePath);
            cn.hutool.core.io.FileUtil.mkParentDirs(destFile); // 只创建目录，不写入内容
            log.info("【文件导出开始】路径: {}", filePath);
            FileUt.writeDatasetExcel(rowList, filePath);
            log.info("【文件导出成功】路径: {}", filePath);
        } catch (Exception e) {
            log.error("【文件导出失败】行业: {}, 问法: {}, 错误: {}", industry.getName(), askMethod, e.getMessage());
        }
    }

    private ExportRow processQuestion(DoubaoResultRecordEntity entity) {
        try {
            AnswerRsp answer = HttpUtil.getAnswer(
                    Config.QWEN_HOST,
                    new QuestionReq(entity.getShopId(),
                            entity.getOriginQuestion(),
                            null,
                            entity.getContext())
            );
            if (answer == null) {
                log.warn("【问题处理】获取答案为空, 问题ID: {}", entity.getId());
                return null;
            }
            return convert(entity, answer);
        } catch (Exception e) {
            log.error("【问题处理异常】问题ID: {}, 异常: {}", entity.getId(), e.getMessage());
            return null;
        }
    }

    private ExportRow convert(DoubaoResultRecordEntity entity, AnswerRsp answer) {
        if (answer == null) {
            return null;
        }
        String askMethodName = "未识别";
        String recognizePointDesc = "未识别";
        if (answer.getAskMethod() != null) {
            askMethodName = answer.getAskMethod().getName();
            recognizePointDesc = answer.getAskMethod().getRecognizePointDesc();
        }
        ExportRow row = new ExportRow();
        row.setContextId(entity.getId());
        row.setContext(entity.getContext());
        row.setQuestion(entity.getOriginQuestion());
        row.setRewriteQuestionNew(answer.getRewriteQuestion());
        row.setMatchAskMethodNew(askMethodName);
        row.setRecognizePointDescNew(recognizePointDesc);
        row.setRewriteQuestionOld(entity.getRewriteQuestion());
        row.setMatchAskMethodOld(entity.getAskMethodName());
        row.setNewOldEquals(Objects.equals(row.getMatchAskMethodNew(), row.getMatchAskMethodOld()) ? 1 : 0);
        row.setRewrite(answer.getRewrite());
        row.setClassifyAllIn(answer.getClassifyAllIn());
        row.setClassify(answer.getClassify());
        row.setAudit(answer.getAudit());
        row.setAuditStatus(StrUtil.isEmpty(answer.getAudit()) ? "0" : "");
        row.setClassifyCount(answer.getClassifyCount());
        row.setClassifyAllInCount(answer.getClassifyAllInCount());
        row.setAuditCount(answer.getAuditCount());
        row.setRewriteCount(answer.getRewriteCount());
        return row;
    }

    // 关闭时清理线程池资源
    @Override
    public void destroy() throws Exception {
        shutdownExecutor(industryAskExecutor, "IndustryAskExecutor");
        shutdownExecutor(questionProcessingExecutor, "QuestionProcessingExecutor");
    }

    private void shutdownExecutor(ExecutorService executor, String name) {
        if (executor != null) {
            try {
                executor.shutdown();
                if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
                    executor.shutdownNow();
                }
                log.info("【线程池关闭】{} 已终止", name);
            } catch (InterruptedException e) {
                executor.shutdownNow();
                Thread.currentThread().interrupt();
                log.warn("【线程池关闭】{} 关闭时被中断", name);
            }
        }
    }
}